package com.sky.controller.notify;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sky.properties.WeChatProperties;
import com.sky.service.OrderService;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;

/**
 * 支付回调相关接口
 */
@RestController
@RequestMapping("/notify")
@Slf4j
public class PayNotifyController {
    @Autowired
    private OrderService orderService;
    @Autowired
    private WeChatProperties weChatProperties;

    /**
     * 支付成功回调
     *
     * @param request  HTTP请求对象，包含支付成功通知的数据
     * @param response HTTP响应对象，用于向微信发送响应
     * @throws Exception 如果处理过程中发生错误
     */
    @RequestMapping("/paySuccess")
    public void paySuccessNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 读取并记录回调数据
        String body = readData(request);
        log.info("支付成功回调：{}", body);

        // 解密回调数据
        String plainText = decryptData(body);
        log.info("解密后的文本：{}", plainText);

        // 解析解密后的JSON数据
        JSONObject jsonObject = JSON.parseObject(plainText);
        String outTradeNo = jsonObject.getString("out_trade_no"); // 商户平台订单号
        String transactionId = jsonObject.getString("transaction_id"); // 微信支付交易号

        // 记录关键订单信息
        log.info("商户平台订单号：{}", outTradeNo);
        log.info("微信支付交易号：{}", transactionId);

        // 处理业务逻辑，如修改订单状态、提醒等
        orderService.paySuccess(outTradeNo);

        // 向微信发送处理完成的响应
        responseToWeixin(response);
    }


    /**
     * 读取数据
     * 通过HttpServletRequest对象读取请求的内容，并将其拼接为一个完整的字符串返回
     * 主要用于处理以流形式提交的数据，如JSON或XML格式的数据
     *
     * @param request HttpServletRequest对象，用于获取请求的输入流
     * @return 读取到的字符串数据，代表请求的完整内容
     * @throws Exception 如果读取过程中发生错误，将抛出异常
     */
    private String readData(HttpServletRequest request) throws Exception {
        // 获取请求的输入流
        BufferedReader reader = request.getReader();
        // 创建一个StringBuilder对象，用于存储读取到的所有行数据
        StringBuilder result = new StringBuilder();
        // 定义一个临时变量，用于存储每行读取到的数据
        String line = null;
        // 循环读取数据，直到输入流的末尾
        while ((line = reader.readLine()) != null) {
            // 如果已经读取了一行以上数据，则在当前行之前添加换行符
            if (result.length() > 0) {
                result.append("\n");
            }
            // 将当前行数据追加到结果字符串中
            result.append(line);
        }
        // 返回拼接完成的字符串
        return result.toString();
    }


    /**
     * 数据解密
     * 该方法用于解密接收到的加密数据体
     * 它首先解析JSON格式的数据体，提取出密文、随机数和关联数据，
     * 然后使用AES算法对密文进行解密，返回解密后的字符串
     *
     * @param body 待解密的数据体，格式为JSON字符串
     * @return 解密后的字符串
     * @throws Exception 如果解密过程中发生错误，将抛出异常
     */
    private String decryptData(String body) throws Exception {
        // 将数据体解析为JSON对象
        JSONObject resultObject = JSON.parseObject(body);
        // 从JSON对象中获取resource字段，其中包含密文等信息
        JSONObject resource = resultObject.getJSONObject("resource");
        // 提取密文
        String ciphertext = resource.getString("ciphertext");
        // 提取随机数
        String nonce = resource.getString("nonce");
        // 提取关联数据
        String associatedData = resource.getString("associated_data");

        // 初始化AES工具类，使用微信API的V3密钥作为解密密钥
        AesUtil aesUtil = new AesUtil(weChatProperties.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        // 密文解密
        String plainText = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8),
                nonce.getBytes(StandardCharsets.UTF_8),
                ciphertext);

        // 返回解密后的字符串
        return plainText;
    }


    /**
     * 给微信响应
     *
     * 该方法用于向微信发送一个表示成功的HTTP响应，其中包括一个状态码和一个消息体
     * 响应状态码设置为200，表示请求成功
     * 响应体中包含一个JSON格式的对象，该对象包含两个属性：code和message，它们的值都设置为"SUCCESS"
     * 这种设计是为了向微信表示我们的服务处理请求没有错误
     *
     * @param response Http响应对象，用于向微信发送响应
     * @throws Exception 如果在发送响应过程中出现错误，则可能会抛出异常
     */
    private void responseToWeixin(HttpServletResponse response) throws Exception{
        // 设置HTTP响应状态码为200，表示成功
        response.setStatus(200);

        // 创建一个用于存储响应数据的HashMap
        HashMap<Object, Object> map = new HashMap<>();
        // 向Map中添加表示成功的code
        map.put("code", "SUCCESS");
        // 向Map中添加表示成功的message
        map.put("message", "SUCCESS");

        // 设置HTTP响应头的Content-type为application/json，表示响应体是JSON格式
        response.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());

        // 将map对象转换为JSON字符串，并写入到响应输出流中
        // 使用UTF-8编码方式将JSON字符串转换为字节，以确保中文字符不会乱码
        response.getOutputStream().write(JSONUtils.toJSONString(map).getBytes(StandardCharsets.UTF_8));

        // 刷新响应缓冲区，确保将数据发送出去
        response.flushBuffer();
    }

}
